/**
 * 
 */
package nz.ac.massey.cs.se400_2013.ass3.gui;

import java.awt.BorderLayout;
import java.util.Collection;
import java.util.Enumeration;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import nz.ac.massey.cs.se400_2013.ass3.Address;
import nz.ac.massey.cs.se400_2013.ass3.Course;
import nz.ac.massey.cs.se400_2013.ass3.ExtendedObjectStore;
import nz.ac.massey.cs.se400_2013.ass3.Paper;
import nz.ac.massey.cs.se400_2013.ass3.Student;

/**
 * @author Chen Here is a sidelist for the GUI to display different models.
 */
public class SideTree extends JPanel{
	
	/**
	 * @serial generated
	 */
	private static final long serialVersionUID = -5711305053173683697L;
	
	private DefaultTreeModel treeModel;
	private JScrollPane scrollPane;
	private JTree tree;
	private Toolbar toolbar;

	private String NODE_Courses = "Courses";
	private DefaultMutableTreeNode courses = new DefaultMutableTreeNode(NODE_Courses);
	
	private ExtendedObjectStore objectStore = ExtendedObjectStore.getInstance();

	AddPaperHandler paperHandler;
	
	
	/**
	 * @author czheng
	 * @param toolbar
	 * Constructor of Sidetree GUI, requires the reference of toolbar menu.
	 */
	public SideTree(Toolbar toolbar) {
		super();
		setLayout(new BorderLayout(0, 0));
		initTree();
		initClickEventListenr();
		this.toolbar = toolbar;
	}

	
	/**
	 * @author czheng
	 * Initialization method of SideTree
	 */
	public void initTree() {

		for(Course course : objectStore.getCourses()){
			DefaultMutableTreeNode courseTree = new DefaultMutableTreeNode(course);
			courses.add(courseTree);
			for(Paper paper : course.getPapers()){
				DefaultMutableTreeNode paperTree = new DefaultMutableTreeNode(paper);
				courseTree.add(paperTree);
				for(Student student : paper.getEnrolledStudents()){
					DefaultMutableTreeNode studentTree = new DefaultMutableTreeNode(student);
					DefaultMutableTreeNode studentAddressTree = new DefaultMutableTreeNode(student.getAddress());
					studentTree.add(studentAddressTree);
					paperTree.add(studentTree);
				}
			}
		}

		treeModel = new DefaultTreeModel(courses);
		tree = new JTree(treeModel);
		scrollPane = new JScrollPane();
		scrollPane.getViewport().add(tree, null);

		this.add(scrollPane);
	}

	
	/**
	 * @author czheng
	 * Initialization method of SideTree Click Event Listener
	 */
	private void initClickEventListenr() {

		// Left mouse click event listener
		this.tree.addTreeSelectionListener(new TreeSelectionListener() {

			@Override
			public void valueChanged(TreeSelectionEvent e) {
				DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
				
				if (node != null) {
					Class nodeClass = node.getUserObject().getClass();
					SideTree.this.setToolBarVisability(nodeClass);
				}
			}
		});
	}


	/**
	 * @author czheng
	 * Delete the current Selected node from SideTree and ObjectSotre.
	 */
	public void deleteCurrentSelection(){
		DefaultTreeModel treeModel = (DefaultTreeModel) this.tree.getModel();
		TreePath[] paths = this.tree.getSelectionPaths();
		for (TreePath path : paths) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
			
			if (node.getParent() != null) {
				treeModel.removeNodeFromParent(node);
				for (Course course : objectStore.getInstance().getCourses()) {
					if (node.getUserObject() == course) {
						objectStore.getCourses().remove(node.getUserObject());
						break;
					}
					for (Paper paper : course.getPapers()) {
						if (node.getUserObject() == paper) {
							objectStore.getCourses().remove(node.getUserObject());
							break;
						}
						for (Student student : paper.getEnrolledStudents()) {
							if (node.getUserObject() == student) {
								objectStore.getCourses().remove(node.getUserObject());
								break;
							}
						}
					}
				}
			}
		}
		
		this.toolbar.setSaveEnabled(true);
	}
	
	
	/**
	 * @author czheng
	 * @param newCourse
	 * Add a new Course instance to Root node and persist it in ObjectStore.
	 */
	public void addCourse(Course newCourse){
		objectStore.getCourses().add(newCourse);
		
		treeModel = (DefaultTreeModel) this.tree.getModel();
		DefaultMutableTreeNode courses = (DefaultMutableTreeNode) treeModel.getRoot();
		courses.add(new DefaultMutableTreeNode(newCourse));
		
		treeModel.reload();
		
		this.toolbar.setSaveEnabled(true);
	}
	
	
	/**
	 * @author czheng
	 * @param newCourse
	 * Add a new Course instance to selected Paper node and persist it in ObjectStore.
	 */
	public void addCourseForPaper(Course newCourse){
		treeModel = (DefaultTreeModel) this.tree.getModel();
		DefaultMutableTreeNode courses = (DefaultMutableTreeNode) treeModel.getRoot();
		TreePath[] paths = this.tree.getSelectionPaths();
		
		for (TreePath path : paths) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
			
			if (node.getParent() != null) {
				for (Course course : objectStore.getInstance().getCourses()) {
					for (Paper paper : course.getPapers()) {
						if (node.getUserObject() == paper) {
							paper.addCourse(newCourse);
							node.add(new DefaultMutableTreeNode(newCourse));
							treeModel.reload(node);
							break;
						}
					}
				}
			}
		}
		
		this.toolbar.setSaveEnabled(true);
	}
	
	
	/**
	 * @param newPaper The new instance of Paper class.
	 * Add a new Paper instance to selected Course node and persist it in ObjectStore.
	 */
	public void addPaperForCourse(Paper newPaper){
		treeModel = (DefaultTreeModel) this.tree.getModel();
		DefaultMutableTreeNode courses = (DefaultMutableTreeNode) treeModel.getRoot();
		TreePath[] paths = this.tree.getSelectionPaths();
		
		for (TreePath path : paths) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
			
			if (node.getParent() != null) {
				for (Course course : objectStore.getInstance().getCourses()) {
					if (node.getUserObject() == course) {
						course.addPaper(newPaper);
						node.add(new DefaultMutableTreeNode(newPaper));
						treeModel.reload(node);
						break;
					}
				}
			}
		}
		
		this.toolbar.setSaveEnabled(true);
	}
	
	/**
	 * @param newStudent The new instance of Student class.
	 * Add a new Student instance to selected Paper node and persist it in ObjectStore.
	 */
	public void addStudentForPaper(Student newStudent){
		treeModel = (DefaultTreeModel) this.tree.getModel();
		DefaultMutableTreeNode courses = (DefaultMutableTreeNode) treeModel.getRoot();
		TreePath[] paths = this.tree.getSelectionPaths();
		
		for (TreePath path : paths) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
			
			if (node.getParent() != null) {
				for (Course course : objectStore.getInstance().getCourses()) {
					for (Paper paper : course.getPapers()) {
						if (node.getUserObject() == paper) {
							paper.addStudent(newStudent);
							node.add(new DefaultMutableTreeNode(newStudent));
							treeModel.reload(node);
							break;
						}
					}
				}
			}
		}
		
		this.toolbar.setSaveEnabled(true);
	}
	
	public Object getCurrentObject(){
		return ((DefaultMutableTreeNode)tree.getLastSelectedPathComponent()).getUserObject();
	}
	/**
	 * @param newAddress The new instance of Address class.
	 * Add a new Address instance to selected Student node and persist it in ObjectStore.
	 */
	public void AddAddressForStudent(Address newAddress){

		treeModel = (DefaultTreeModel) this.tree.getModel();
		DefaultMutableTreeNode courses = (DefaultMutableTreeNode) treeModel.getRoot();
		TreePath[] paths = this.tree.getSelectionPaths();
		
		for (TreePath path : paths) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
			
			if (node.getParent() != null) {
				for (Course course : objectStore.getInstance().getCourses()) {
					for (Paper paper : course.getPapers()) {
						for (Student student : paper.getEnrolledStudents()) {
							if (node.getUserObject() == student) {
								student.setAddress(newAddress);
								node.add(new DefaultMutableTreeNode(newAddress));
								treeModel.reload(node);
								break;
							}
						}
					}
				}
			}
		}
		
		this.toolbar.setSaveEnabled(true);
	
	}
	
	/**
	 * @author czheng
	 * The method for saving changes.
	 * Save the Change(s) of the side tree object and persist them in ObjectStore.
	 */
	public void saveChanges(){
		treeModel = (DefaultTreeModel) this.tree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
		TreePath[] paths = this.tree.getSelectionPaths();
		
		for (TreePath path : paths) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
			this.treeModel.reload(node);
		}
		toolbar.setSaveEnabled(false);
		//TODO traversal the entire tree and put everything in objectStore.
		
	}

	public void setToolBarVisability(Class nodeClass){
		
		if(nodeClass == Paper.class){
			this.toolbar.setPaperEnabled(false);
			this.toolbar.setStudentEnabled(true);
			this.toolbar.setDeleteEnabled(true);
		}
		else if(nodeClass == Student.class){
			this.toolbar.setPaperEnabled(false);
			this.toolbar.setStudentEnabled(false);
			this.toolbar.setDeleteEnabled(true);
		}
		else if(nodeClass == Course.class){
			this.toolbar.setStudentEnabled(false);
			this.toolbar.setPaperEnabled(true);
			this.toolbar.setDeleteEnabled(true);
		}
		else{
			this.toolbar.setStudentEnabled(false);
			this.toolbar.setPaperEnabled(false);
			this.toolbar.setDeleteEnabled(false);
		}
	}
	
	
	public void addTreeSelectionHandler(TreeSelectionListener handler){
		this.tree.addTreeSelectionListener(handler);
	}
}
